/*********************************************************
 * 初学之家(http://www.g2room.com)，提供Java、Javascript（js）、Jquery、
 * 等一些工具或常用功能的实现例子代码，希望能给初学者提供学习和工作上的帮助，
 * 也希望有想提供源代码的朋友能联系我，一起努力，提供更多、更全面、更详细的
 * 一些初学代码例子及经验，帮助更多的人。
 * 
 * 我的联系方式：E-Mail：g2room@163.com
 * 网址：http://www.g2room.com
 * QQ：天涯（1173930590）
 * QQ交流群：323642758
 * 
 * 本站内容为提供各种java、javascript(JS)常用的工具源代码、实例（示例）、
 * 基本配置、教程、手册等；目前Java代码提供的工具（或转换）例子代码如下：
 * BASE64转换工具、bytes相关操作、email收发、文件操作（读写、拷贝、遍历、
 * 多线程copy等）、json格式转换、日志（Log4j）操作工具、Lucene搜索引擎的
 * 创建索引和搜索、各种不同Map的使用、定时器（Quartz）的使用例子、Socket的
 * 连接传输数据例子、WebService的例子及一些常用的工具类如String、Date及
 * JDK自带的一些工具类及函数的使用例子。
 * 
 * 说明：如需直接使用本站的例子代码，请保留此说明
 * 
 ********************************************************/
package com.g2room.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 
 *
 * @createTime: Jul 9, 2013 11:04:36 AM
 * @author: <a href="mailto:g2room@163.com">天涯</a>
 * @version: 0.1
 * @lastVersion: 0.1
 * @updateTime: 
 * @updateAuthor: <a href="mailto:g2room@163.com">天涯</a>
 * @changesSum: 
 * 
 */
public class Main {
	public static void main(String[] args) {
		/**
		 	1、线程的名字，一个运行中的线程总是有名字的，名字有两个来源，一个是虚拟机自己给的名字，一个是你自己的定的名字。在没有指定线程名字的情况下，虚拟机总会为线程指定名字，并且主线程的名字总是mian，非主线程的名字不确定。 
			2、线程都可以设置名字，也可以获取线程的名字，连主线程也不例外。 
			3、获取当前线程的对象的方法是：Thread.currentThread()； 
			4、在上面的代码中，只能保证：每个线程都将启动，每个线程都将运行直到完成。一系列线程以某种顺序启动并不意味着将按该顺序执行。对于任何一组启动的线程来说，调度程序不能保证其执行次序，持续时间也无法保证。 
			5、当线程目标run()方法结束时该线程完成。 
			6、一旦线程启动，它就永远不能再重新启动。只有一个新的线程可以被启动，并且只能一次。一个可运行的线程或死线程可以被重新启动。 
			7、线程的调度是JVM的一部分，在一个CPU的机器上上，实际上一次只能运行一个线程。一次只有一个线程栈执行。JVM线程调度程序决定实际运行哪个处于可运行状态的线程。 众多可运行线程中的某一个会被选中做为当前线程。可运行线程被选择运行的顺序是没有保障的。 
			8、尽管通常采用队列形式，但这是没有保障的。队列形式是指当一个线程完成“一轮”时，它移到可运行队列的尾部等待，直到它最终排队到该队列的前端为止，它才能被再次选中。事实上，我们把它称为可运行池而不是一个可运行队列，目的是帮助认识线程并不都是以某种有保障的顺序排列唱呢个一个队列的事实。 
			9、尽管我们没有无法控制线程调度程序，但可以通过别的方式来影响线程调度的方式。
		 */
//		runnableExcute();
//		
//		threadExcute();
		
//		callableExcute();
		System.out.println("001041001281900001000005380100000538ccc".length());
	}
	/**
	 * 使用Callable的方式实现多线程并返回执行结果值
	 *
	 * @auther <a href="mailto:g2room@163.com">天涯</a>
	 * Sep 11, 2013 5:42:11 PM
	 */
	public static void callableExcute(){
		int num = 50000;
		// 使用ExecutorService、Callable、Future实现有返回结果的多线程
		// 实际上都是属于Executor框架中的功能类。
		// newFixedThreadPool：创建固定数目线程的线程池
		ExecutorService pool = Executors.newFixedThreadPool(num);
//		//创建一个使用单个 worker 线程的 Executor，以无界队列方式来运行该线程。
//		ExecutorService pool = Executors.newSingleThreadExecutor();
//		// 创建一个可缓存的线程池，调用execute 将重用以前构造的线程（如果线程可用）。
//		// 如果现有线程没有可用的，则创建一个新线程并添加到池中。
//		// 终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
//		ExecutorService pool = Executors.newCachedThreadPool()
//		// 创建一个支持定时及周期性的任务执行的线程池，多数情况下可用来替代Timer类。
//		ExecutorService pool = Executors.newScheduledThreadPool(3);
		TestCallable callable = new TestCallable(num);
		// 使用Future作为返回值对象
		Future<String> fu = pool.submit(callable);
		try {
			System.out.println(fu.get().toString());
			// 关闭
			if(pool.isShutdown()) {
				System.out.println("执行完毕，关闭线程成功！");
			} else {
				System.out.println("执行不完毕，关闭线程成功！");
			}
			pool.shutdown();
			// isTerminated---所有任务执行完后，pool shutdown成功则返回true
			if(pool.isShutdown()) {
				System.out.println("执行完毕，关闭线程成功！");
			} else {
				System.out.println("执行不完毕，关闭线程成功！");
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
//		// 测试执行多个
//		pool = Executors.newFixedThreadPool(num);
//		List<Future<String>> futureList = new ArrayList<Future<String>>();
//		for (int i = 0; i < num; i++) {
//			TestCallable callable1 = new TestCallable(2);
//			Future<String> future = pool.submit(callable1);
//			futureList.add(future);
//		}
//		for (Future<String> future : futureList) {
//			try {
//				System.out.println(future.get().toString());
//			} catch (InterruptedException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			} catch (ExecutionException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//			pool.shutdown();
//			// isTerminated---所有任务执行完后，pool shutdown成功则返回true
//			while (pool.isTerminated()) {
//				System.out.println("=================");
//			} 
//		 }
	}
	/**
	 * 使用继承Thread方式的多线程例子
	 *
	 * @auther <a href="mailto:g2room@163.com">天涯</a>
	 * Sep 11, 2013 5:26:06 PM
	 */
	public static void threadExcute() {
		// 使用Thread的方式实现多线程
		TestThread testThread = new TestThread(4);
		testThread.start();
	}
	
	/**
	 * 使用实现Runnable接口的多线程例子
	 *
	 * @auther <a href="mailto:g2room@163.com">天涯</a>
	 * Sep 11, 2013 5:25:18 PM
	 */
	public static void runnableExcute(){
		// 使用Runnable的方式
		TestRunnable runnableThread = new TestRunnable(3);
		// new Thread的第一个参数为要执行的的类
		// 第二个参数为线程名称
		Thread thread = new Thread(runnableThread, "runnable");
		/**
		 * 在线程的Thread对象上调用start()方法，而不是run()或者别的方法。
		 * 在调用start()方法之前：
		 * 		线程处于新状态中，新状态指有一个Thread对象，但还不是真正的线程。
		 * 在调用start()方法之后，发生了一系列复杂的事情：
		 * 启动新的执行线程（具有新的调用栈）； 
		 * 该线程从新状态转移到可运行状态；
		 * 当该线程获得机会执行时，其目标run()方法将运行。
		 * 
		 * 注意：对Java来说，run()方法没有任何特别之处。
		 * 像main()方法一样，它只是新线程知道调用的方法名称(和签名)。
		 * 因此，在Runnable上或者Thread上调用run方法是合法的。
		 * 但并不启动新的线程。
		 */
		thread.start();
	}
}
